﻿using System;
using System.Collections.Generic;
using System.Linq;
using Skynet.CommonLibrary.Extension;
using System.Reflection;
using System.ServiceModel;
using Skynet.CommonLibrary.Extension.Serialize;
using System.Xml.Linq;
using System.IO;
using System.Data;

namespace Skynet.CommonLibrary.WCF
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
        ConcurrencyMode = ConcurrencyMode.Single,
        UseSynchronizationContext = false)]  //解除线程的关联性,更好的支持并发
    public class DataAccessCenter : BaseCenter, IDataAccessCenter
    {
        public DataAccessCenter() : base("DllName") { }

        #region IDataAccessCenter 成员

        public byte[] FindEntity(ParamesEntity data, string expression)
        {
            if (expression == null)
                throw new Exception("表达式不能为空");

            if (data != null)
            {
                System.Linq.Expressions.Expression pression = new ExpressionSerializer().Deserialize(XElement.Load(new StringReader(expression)));
                List<object> list = new List<object>();
                if (data.Values != null)
                {
                    list.AddRange(data.Values);
                }
                list.Add(pression);
                data.Values = list.ToArray();
            }

            object result = MethodInvoke<object>(data);
            if (result != null)
            {
                return result.SerializeData();
            }
            return null;
        }

        public byte[] FindData(ParamesEntity data)
        {
            object result = MethodInvoke<object>(data);
            if (result != null)
            {
                return result.SerializeData();
            }
            return null;
        }

        public bool ModifyData(ParamesEntity data)
        {
            return MethodInvoke<bool>(data);
        }

        public object GetObject(ParamesEntity data)
        {
            return MethodInvoke<object>(data);
        }

        public DataTable GetTable(ParamesEntity data)
        {
            return MethodInvoke<DataTable>(data);
        }

        public void ExecuteCommand(ParamesEntity data)
        {
            MethodInvoke(data);
        }
        #endregion

        private T MethodInvoke<T>(ParamesEntity data)
        {
            if (data == null)
                throw new Exception("参数不能为空");
            data.Verity();
            MethodInfo info;

            if (data.Values == null || data.Values.Length == 0)
            {
                object obj = AssemblyLoad(data, out info, false);
                return (T)info.Invoke(obj, null);
            }
            try
            {
                data.Values = (from o in data.Values 
                               let bytes = o as byte[] 
                               select null != bytes ? bytes.DeserializeData<object>() : o).ToArray();
                object obj = AssemblyLoad(data, out info, false);
                return (T)info.Invoke(obj, data.Values);
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("调用方法出错({0}),内容：{1}",
                                                  data.MethodName,
                                                  ex.InnerException != null ? ex.InnerException.Message : ex.Message));
            }
        }
        private void MethodInvoke(ParamesEntity data)
        {
            if (data == null)
                throw new Exception("参数不能为空");
            data.Verity();
            MethodInfo info;

            if (data.Values == null || data.Values.Length == 0)
            {
                object obj = AssemblyLoad(data, out info, false);
                info.Invoke(obj, null);
            }
            else
            {
                try
                {
                    data.Values = (from o in data.Values 
                                   let bytes = o as byte[] 
                                   select null != bytes ? bytes.DeserializeData<object>() : o).ToArray();
                    object obj = AssemblyLoad(data, out info, false);
                    info.Invoke(obj, data.Values);
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("调用方法出错({0}),内容：{1}",
                        data.MethodName,
                        ex.InnerException != null ? ex.InnerException.Message : ex.Message));
                }
            }
        }
    }

    public abstract class BaseCenter
    {
        readonly string _dllName = string.Empty;
        readonly string _dllPath = string.Empty;

        protected BaseCenter(string dllPath, string dllName)
        {
            _dllPath = dllPath;
            _dllName = dllName;
        }

        protected BaseCenter(string dllConfig)
        {
            _dllName = System.Configuration.ConfigurationManager.AppSettings[dllConfig];
        }
        protected object AssemblyLoad(ParamesEntity data, out MethodInfo info, bool isOut)
        {
            string path = string.Format("{0}\\{1}.dll", _dllPath == string.Empty ? AppDomain.CurrentDomain.BaseDirectory : _dllPath, _dllName);
            Assembly assembly = HttpRuntimeCache.GetCache<Assembly>(path);
            Type objType;
            object obj;
            if (null == assembly)
            {
                assembly = Assembly.LoadFile(path);
                HttpRuntimeCache.SetCache(path, assembly, 10);
            }
            try
            {
                objType = assembly.GetType(_dllName + "." + data.ClassName, true, true);
                obj = objType.CreateInstance();
            }
            catch
            {
                throw new Exception(string.Format("找不到该程序集下的具体实现({0})", _dllName + "." + data.ClassName));
            }
            ////设置属性
            //obj.SetValue("UserName", data.UserName);

            try
            {
                info = objType.GetOverLoadMethodInfo(data.MethodName, data.Values, false);
            }
            catch
            {
                throw new Exception(string.Format("不存在接口对应的具体实现({0}),请检查接口.", data.MethodName));
            }
            return obj;
        }
    }
}
